package site.xuqing.appbus;

import java.util.List;

import site.xuqing.appbus.listener.OnMsgListener;
import site.xuqing.appbus.utils.RouteUtil;

/**
 * @author xuqing
 * @Description Client
 * @createTime 2022年01月26日 16:08:49
 */
public class Client {
    private OnMsgListener mOnMsgListener;
    private final Server mServer;
    private final String route;
    
    public Client(String route, Server server) {
        this.route = route;
        this.mServer = server;
    }
    
    /**
     * 发送消息
     *
     * @param clazz 发送消息到Class<?>
     * @param data  需要发送的消息
     * @param <T>   需要发送消息的类型
     * @return Client
     */
    public <T> Client send(T data, Class<?> clazz) {
        send(data, RouteUtil.getRoute(clazz));
        return this;
    }
    
    /**
     * 发送消息
     *
     * @param object 发送消息到Object
     * @param data   需要发送的消息
     * @param <T>    需要发送消息的类型
     * @return Client
     */
    public <T> Client send(T data, Object object) {
        send(data, RouteUtil.getRoute(object));
        return this;
    }
    
    /**
     * 发送消息
     *
     * @param targetRoute 发送消息到绑定targetRoute的对象
     * @param data        需要发送的消息
     * @param <T>         需要发送消息的类型
     * @return Client
     */
    public <T> Client send(T data, String targetRoute) {
        List<Client> clients = mServer.getClient(targetRoute);
        if (clients != null) {
            for (Client client:clients) {
                OnMsgListener<T> onMsgListener = client.getOnMsgListener();
                if (onMsgListener != null) {
                    onMsgListener.onMsg(data);
                } else {
                    setMsgToQueue(targetRoute, data);
                }
            }
        } else {
            setMsgToQueue(targetRoute, data);
        }
        return this;
    }
    
    /**
     * 发送给多个监听对象
     *
     * @param data    需要发送的消息对象
     * @param objects 需要发送的目标对象
     * @param <T>     消息对象的类型
     * @return 连接器
     */
    public <T> Client send(T data, Object... objects) {
        for (Object object : objects) {
            if (object instanceof String) {
                send(data, (String) object);
            } else if (object instanceof Class) {
                send(data, (Class<?>) object);
            } else {
                send(data, object);
            }
        }
        return this;
    }
    
    /**
     * 发送消息给说有已注册的对象
     *
     * @param data 消息对象
     * @param <T>  消息类型
     * @return Client
     */
    public <T> Client sendAll(T data) {
        List<Client> clients = mServer.getAllClient();
        for (Client client : clients) {
            if (client != null) {
                OnMsgListener<T> onMsgListener = client.getOnMsgListener();
                if (onMsgListener != null) {
                    onMsgListener.onMsg(data);
                } else {
                    setMsgToQueue(client.getRoute(), data);
                }
            }
        }
        return this;
    }
    
    /**
     * 设置接收消息监听
     *
     * @param onMsgListener OnMsgListener
     * @param <T>           监听的数据类型
     */
    public <T> void setOnMsgListener(OnMsgListener<T> onMsgListener) {
        this.mOnMsgListener = onMsgListener;
        List<T> msgList = mServer.getMsgFromQueue(route);
        if (msgList != null && msgList.size() > 0) {
            for (T data : msgList) {
                if (onMsgListener != null) {
                    onMsgListener.onMsg(data);
                }
            }
        }
    }
    
    /**
     * 获取接收消息的监听
     *
     * @param <T> 监听的数据类型
     * @return OnMsgListener
     */
    public <T> OnMsgListener<T> getOnMsgListener() {
        return mOnMsgListener;
    }
    
    /**
     * 获取当前Client的路由
     *
     * @return Route
     */
    public String getRoute() {
        return route;
    }
    
    /**
     * 把消息设置到队列中
     *
     * @param route route
     * @param data  需要设置的消息
     * @param <T>   消息类型
     */
    private <T> void setMsgToQueue(String route, T data) {
        mServer.addMsgToQueue(route, data);
    }
    
    @Override
    public int hashCode() {
        return super.hashCode();
    }
    
    @Override
    public boolean equals(Object obj) {
        return super.equals(obj);
    }
}
